package com.wu.qqserver.service;



import com.wu.qqcommon.Message;
import com.wu.qqcommon.MessageType;
import com.wu.qqcommon.User;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;

/*

 */
public class QQServer {

    private ServerSocket serverSocket;

    private static ConcurrentHashMap<String,User> validUser = new ConcurrentHashMap<>();

    static {//在静态代码块中模拟数据库 实现多用户操作
        validUser.put("96",new User("96","123456"));
        validUser.put("97",new User("97","123456"));
        validUser.put("98",new User("98","123456"));
        validUser.put("至尊宝",new User("至尊宝","123456"));
        validUser.put("紫霞仙子",new User("紫霞仙子","123456"));
        validUser.put("孙悟空",new User("孙悟空","123456"));

    }
    //验证用户是否有效的方法，其实我们也可以搞一个单点登录问题，，因为我们存储的集合管理的线程里有scoket,userId，这样
    //我们就可以根据userId 判断是否存在这个线程名字 有的话就不让登录了，这是最原始的单点登录问题解决，现在有很多框架可用
    private boolean checkUser(String userId,String passWd){
        User user = validUser.get(userId);
        if (user==null){
            return false;
        }
        if (!user.getPassWd().equals(passWd)){
            return false;
        }
        return true;
    }

    public QQServer(){
        //注意：端口看可以写在配置文件中
        try {
            System.out.println("服务器正在监听9999端口。。。。");
            //启动我们的推送服务
            new Thread(new SendNewsToAllOnLineUserService()).start();

            serverSocket = new ServerSocket(9999);

            while (true){//当和某个客户端建立连接后，会继续监听，所以用true，，其实当你写到这个时就跟客户端有点类似了
                Socket socket = serverSocket.accept();
                //得到socket关联的ObjectInputStream
                ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
                //得到客户端发送的user对象
                User user= (User) ois.readObject();

                //得到socket关联的ObjectInputStream
                ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());

                //创建一个message用以回复客户端
                Message message = new Message();
                    //这样就不用写死了用户
//                if (user.getUserId().equals("96") && user.getPassWd().equals("0906")){
                if (checkUser(user.getUserId(),user.getPassWd())){
                    message.setMesType(MessageType.MESSAGE_LOGIN_SUCCEED);
                    //将message返还给客户端
                    oos.writeObject(message);
                    //创建一个线程，和客户端保持通讯，该线程持有socket对象
                    ServerConnectClientThread serverConnectClientThread = new ServerConnectClientThread(socket, user.getUserId());
                    serverConnectClientThread.start();
                    //把该线程对象放入一个集合中，用于管理
                    ManageServerConnectClientThread.addServerConnectClientThread(user.getUserId(),serverConnectClientThread);


                    //当用户成功登录验证成功后我们来判断，是否有它的离线消息，有的话就推送
                    if (OffLineNewsToOneUserService.userIdIsEmpty(user.getUserId())){
                        ArrayList<Message> offNews = OffLineNewsToOneUserService.getOffNews(user.getUserId());
                        for (Message aNew : offNews) {
                            //遍历发送消息
                            aNew.setMesType(MessageType.MESSAGE_COMM_MES);
                            ObjectOutputStream oosOffNews = new ObjectOutputStream(ManageServerConnectClientThread
                                    .getServerConnectClientThread(user.getUserId())
                                    .getSocket()
                                    .getOutputStream());
                            oosOffNews.writeObject(aNew);
                        }
                        //发完之后 将消息从离线消息集合中删除
                        OffLineNewsToOneUserService.remove(user.getUserId());
                    }


                }else {//登录失败
                    System.out.println("登陆失败..."+user.getUserId());
                        message.setMesType(MessageType.MESSAGE_LOGIN_FAIL);
                        oos.writeObject(message);
                        socket.close();
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //如果服务端 推出了while询缓 ，说明服务端不再监听了 那就要关闭serverSocket
            try {
                serverSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}
